// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

#include <doctest.h>

#include <experimental/filesystem>

#include "coin2/app/driver.h"
#include "coin2/app/driver.pb.h"
#include "coin2/base/config/app_config.h"
#include "coin2/strategy/strategy.h"

using coin2::app::Driver;
using coin2::app::DriverConfig;
using coin2::exchange::base::feed::FeedUpdate;
using coin2::strategy::IStrategy;

struct Stat {
  uint64_t trade = 0;
  uint64_t book = 0;
  double pq = 0;
  double qty = 0;
  double ask0pq = 0;
  double bid0pq = 0;
};

class StatCalculator : public IStrategy {
 public:
  void onTradeFeed(const FeedUpdate& upd) override {
    stat_.trade++;
    const auto& trade = upd.trade();
    stat_.pq += trade.price * trade.fill_qty;
    stat_.qty += trade.fill_qty;
  }
  void onBookFeed(const FeedUpdate& upd) override {
    stat_.book++;
    const auto& book = upd.book();
    if (book.Ask0()) {
      stat_.ask0pq += book.Ask0()->price * book.Ask0()->qty;
    }
    if (book.Bid0()) {
      stat_.bid0pq += book.Bid0()->price * book.Bid0()->qty;
    }
  }
  Stat stat_;
};

void run(const std::experimental::filesystem::path& path, Stat answer) {
  DriverConfig config = coin2::base::config::DriverConfigFromJson(path);
  StatCalculator s;
  Driver driver(config, &s);
  driver.Run(false);

  DOCTEST_CHECK(s.stat_.trade == answer.trade);
  DOCTEST_CHECK(s.stat_.book == answer.book);
  DOCTEST_CHECK(s.stat_.pq == doctest::Approx(answer.pq));
  DOCTEST_CHECK(s.stat_.qty == doctest::Approx(answer.qty));
  DOCTEST_CHECK(s.stat_.ask0pq == doctest::Approx(answer.ask0pq));
  DOCTEST_CHECK(s.stat_.bid0pq == doctest::Approx(answer.bid0pq));
}

// Re-organize configs if there are many

DOCTEST_TEST_CASE("read raw-feed") {
  DOCTEST_SUBCASE("spot coinone") {
    run("data/test/config/feed-raw-coinone.json",
        Stat{68, 10800, 44949823.2868560031, 17055.606, 19162890190.8593025208,
             13655979901.0048942566});
  }
  DOCTEST_SUBCASE("spot okex") {
    run("data/test/config/feed-raw-okex.json",
        Stat{7089, 500798, 6798689.7857875656, 114224249.8228256702,
             760288585.7917650938, 671376886.2630038261});
  }
  DOCTEST_SUBCASE("futures okex") {
    run("data/test/config/feed-raw-futures-okex.json",
        Stat{4673, 537825, 3507019520.5690479279, 998745.0,
             1625842713229.0595703125, 1369666814516.7043457031});
  }
  DOCTEST_SUBCASE("spot quoinex") {
    run("data/test/config/feed-raw-quoinex.json",
        Stat{24, 6029, 4450772.3663543602, 13.93839692, 2563369798.3803539276,
             2474880848.8877506256});
  }
  DOCTEST_SUBCASE("spot upbit") {
    run("data/test/config/feed-raw-upbit.json",
        Stat{562, 11903, 281641986.7902960777, 956927.1558828903,
             34903142449.1423797607, 89817129691.2691192627});
  }
}

DOCTEST_TEST_CASE("read fastfeed") {
  DOCTEST_SUBCASE("spot binance") {
    run("data/test/config/feed-fastfeed-binance.json",
        Stat{9071, 39483, 7962771.5804001009, 4421.8592999999,
             263545701.9729955494, 298790995.8125040531});
  }
  DOCTEST_SUBCASE("futures bitmex") {
    run("data/test/config/feed-fastfeed-bitmex.json",
        Stat{1638, 428, 15.96027366, 7434092.0, 484.11364803, 31.4422834});
  }
  DOCTEST_SUBCASE("spot upbit") {
    run("data/test/config/feed-fastfeed-upbit.json",
        Stat{25713, 89483, 13525959433.3890743256, 5415538.3775000107,
             800020307252.2521972656, 927441848094.8939208984});
  }
}
